package com.example.rabbitmq.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ 配置类
 * 用于定义消息队列、交换机、绑定关系以及消息转换器等核心组件
 * 实现基于发布/订阅（Publish/Subscribe）模式的消息通信
 */
@Configuration // 标识为Spring配置类，Spring容器会自动扫描并加载该配置
public class RabbitMQConfig {

    /**
     * 配置消息转换器
     * 使用Jackson2JsonMessageConverter将消息对象序列化为JSON格式，便于跨语言/系统传输
     * 替代默认的SimpleMessageConverter（默认使用Java序列化，存在安全性和兼容性问题）
     * @return 消息转换器实例
     */
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定义发布/订阅模式的交换机（Fanout Exchange）
     * Fanout交换机将接收到的消息广播到所有绑定的队列，忽略路由键（Routing Key）
     * 适合需要将同一消息发送给多个消费者的场景（如通知、日志分发等）
     * @return Fanout类型的交换机实例，名称为"pub/sub.exchange"
     */
    @Bean
    public Exchange pubsubExchange() {
        // 使用ExchangeBuilder构建Fanout交换机，指定交换机名称并构建
        return ExchangeBuilder.fanoutExchange("pub/sub.exchange").build();
    }

    /**
     * 定义邮件队列
     * 用于接收并存储需要处理邮件发送的消息
     * @return 队列实例，名称为"email.queue"
     */
    @Bean
    public Queue emailQueue() {
        // 创建一个持久化、非排他、非自动删除的队列（默认配置）
        return new Queue("email.queue");
    }

    /**
     * 定义短信队列
     * 用于接收并存储需要处理短信发送的消息
     * @return 队列实例，名称为"sms.queue"
     */
    @Bean
    public Queue smsQueue() {
        return new Queue("sms.queue");
    }

    /**
     * 绑定邮件队列到发布/订阅交换机
     * 建立队列与交换机之间的关联关系，使交换机能够将消息路由到队列
     * @return 绑定关系实例
     */
    @Bean
    public Binding bindingEmail() {
        // 将emailQueue队列绑定到pubsubExchange交换机，Fanout模式下路由键为空字符串
        return BindingBuilder.bind(emailQueue()).to(pubsubExchange()).with("").noargs();
    }

    /**
     * 绑定短信队列到发布/订阅交换机
     * @return 绑定关系实例
     */
    @Bean
    public Binding bindingSms() {
        // 将smsQueue队列绑定到pubsubExchange交换机
        return BindingBuilder.bind(smsQueue()).to(pubsubExchange()).with("").noargs();
    }
}